﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using Sushi.Core;
using Exception = System.Exception;//needed because sushi also has an exception class

namespace Sushi.Sample.Service.Data
{
   public class CounterXMLFile
   {
      private string _fileName;
      private string _customerId;
      private DateTime _runDate;
      private string _reportType;


      public CounterXMLFile(string fileName)
      {
         _fileName = fileName;

			if (!File.Exists(_fileName)) throw new SushiServiceException("File not found: " + _fileName);

         //split just the name of the file into parts 
         string[] parts = Path.GetFileNameWithoutExtension(_fileName).Split('-');
			if (parts.Length != 3) throw new SushiServiceException("Filename not formatted as YYYYMMDD-ReportType-CustomerId.xml: " + _fileName);
         _runDate = DateTime.ParseExact(parts[0], "yyyyMMdd", CultureInfo.InvariantCulture);
         _reportType = parts[1];
         _customerId = parts[2]; 
      }

      public string FileName
      {
         get { return _fileName; }
      }

      public string CustomerId
      {
         get { return _customerId; }
      }

      public DateTime RunDate
      {
         get { return _runDate; }
      }

      public string ReportType
      {
         get { return _reportType; }
      }

      public ReportItem[] ReadReportItems()
      {
         //create temporary list of ReportItems to hold results
         var reportItems = new List<ReportItem>();

         FileStream stream = new FileStream(_fileName, FileMode.Open);
         XPathDocument document = new XPathDocument(stream);
         XPathNavigator navigator = document.CreateNavigator();
         XmlNamespaceManager manager = new XmlNamespaceManager(navigator.NameTable);
         manager.AddNamespace("c", "http://www.niso.org/schemas/counter");

         XPathNodeIterator reportItemNodes = navigator.Select("/c:Reports/c:Report[1]/c:Customer/c:ReportItems", manager);


         foreach (XPathNavigator reportItemNode in reportItemNodes)
         {
            var reportItem = new ReportItem();

            //the first three cells are "header" information
            reportItem.ItemName = reportItemNode.SelectSingleNode("c:ItemName", manager).Value;
            reportItem.ItemPublisher = reportItemNode.SelectSingleNode("c:ItemPublisher", manager).Value;
            reportItem.ItemPlatform = reportItemNode.SelectSingleNode("c:ItemPlatform", manager).Value;
            reportItem.ItemDataType = reportItemNode.SelectSingleNode("c:ItemDataType", manager).Value;

            var identifiers = new List<Identifier>();

            //create identifiers in a temporary list for the remaining row cells
            XPathNodeIterator identifierNodes = reportItemNode.Select("c:ItemIdentifier", manager);
            foreach (XPathNavigator identifierNode in identifierNodes)
            {
               identifiers.Add(new Identifier()
                                  {
                                     Type = identifierNode.SelectSingleNode("c:Type", manager).Value,
                                     Value = identifierNode.SelectSingleNode("c:Value", manager).Value
                                  }
                  );
            }

            var itemPerformances = new List<Metric>();

            XPathNodeIterator performanceNodes = reportItemNode.Select("c:ItemPerformance", manager);
            foreach (XPathNavigator performanceNode in performanceNodes)
            {
               var metric = new Metric();

               metric.Category = performanceNode.SelectSingleNode("c:Category", manager).Value;
               string beginPeriod = performanceNode.SelectSingleNode("c:Period/c:Begin", manager).Value;
               string endPeriod = performanceNode.SelectSingleNode("c:Period/c:End", manager).Value;
               metric.Period = new DateRange()
                                  {
                                     Begin = DateTime.ParseExact(beginPeriod, "yyyy-MM-dd", CultureInfo.InvariantCulture),
                                     End = DateTime.ParseExact(endPeriod, "yyyy-MM-dd", CultureInfo.InvariantCulture)
                                  };


               var metricIntances = new List<PerformanceCounter>();
               XPathNodeIterator metricIntanceNodes = performanceNode.Select("c:Instance", manager);
               foreach (XPathNavigator metricIntanceNode in metricIntanceNodes)
               {
                  metricIntances.Add(new PerformanceCounter()
                                     {
                                        MetricType = metricIntanceNode.SelectSingleNode("c:MetricType", manager).Value,
                                        Count = (float)metricIntanceNode.SelectSingleNode("c:Count", manager).ValueAsDouble
                                     }
                                    );

               }

               //convert the temporary metric instances list to an array and assign to the metric
               metric.Instance = metricIntances.ToArray();

               //now append this metric to the performance's list
               itemPerformances.Add(metric);
            }

            //convert the temporary performances list to an array and assign to the reportItem
            reportItem.ItemPerformance = itemPerformances.ToArray();

            //convert the temporary Identifiers list to an array and assign to the reportItem
            reportItem.ItemIdentifier = identifiers.ToArray();

            //add the completed reportItem object to the list
            reportItems.Add(reportItem);
         }

         return reportItems.ToArray();
      }
   }
}
